Rückblick: In Teil 2 dieses Tutorials wurde ein Model mit sehr simplem Federated Learning traininert. Es war dabei notwendig, dass jeder Daten-Besitzer dem Model-Besitzer seine persönlichen Gradienten anvertraute.
Beschreibung: In diesem Tutorial werden die fortgeschrittenen Werkzeuge aus Teil 3 genutzt, um mit ihnen die Gradienten bei einem vertrauenswürdigen "sicheren Helfer" zu sammeln, bevor das finale Model zum Model-Besitzer zurück gesendet wird.
Auf diese Weise kann nur der sichere Helfer sehen, wer welche Gradienten geschickt hat. Der Model-Besitzer kann anschließend nur erkennen wie sich das Model verändert hat, dies jedoch NICHT auf einen der Helfer (Alice oder Bob) zurückführen. Dies sorgt für grundlegende Privatsphäre.
Autoren:
Übersetzer:
In [ ]:
import torch
import syft as sy
import copy
hook = sy.TorchHook(torch)
from torch import nn, optim
Zuerst werden zwei Daten-Besitzer (Bob und Alice) erstellt, welche jeweils einen kleinen Anteil der Daten erhalten. Außerden wird eine sichere Maschine (secure_worker
) eingesetzt. In der Praxis kann dies sichere Hardware (wie Intels SGX) oder ein vertrauenswürdiger Vermittler sein.
In [ ]:
# create a couple workers
bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
secure_worker = sy.VirtualWorker(hook, id="secure_worker")
# A Toy Dataset
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)
# get pointers to training data on each worker by
# sending some training data to bob and alice
bobs_data = data[0:2].send(bob)
bobs_target = target[0:2].send(bob)
alices_data = data[2:].send(alice)
alices_target = target[2:].send(alice)
In [ ]:
# Iniitalize A Toy Model
model = nn.Linear(2,1)
In [ ]:
bobs_model = model.copy().send(bob)
alices_model = model.copy().send(alice)
bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)
alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)
In [ ]:
for i in range(10):
# Train Bob's Model
bobs_opt.zero_grad()
bobs_pred = bobs_model(bobs_data)
bobs_loss = ((bobs_pred - bobs_target)**2).sum()
bobs_loss.backward()
bobs_opt.step()
bobs_loss = bobs_loss.get().data
# Train Alice's Model
alices_opt.zero_grad()
alices_pred = alices_model(alices_data)
alices_loss = ((alices_pred - alices_target)**2).sum()
alices_loss.backward()
alices_opt.step()
alices_loss = alices_loss.get().data
print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss))
Da nun alle Daten-Besitzer ein eigenes teiltrainiertes Model besitzen, ist es an der Zeit diese auf eine sichere Weise zusammenzuführen. Dies wird erreicht, indem Alice und Bob ihre Modele zum (vertrauenswürdigen) sicheren Server senden.
Es ist anzumerken, dass mit dieser API jedes der Modele DIREKT zum secure_worker
gesendet wird und der Model-Besitzer die einzelnen Modele nie zu Gesicht bekommt.
In [ ]:
alices_model.move(secure_worker)
In [ ]:
bobs_model.move(secure_worker)
Der letzte Schritt dieser Trainings-Epoche ist die trainierten Modele von Bob und Alice zu mitteln und die so erhaltenen Gewichte für das globale Model zu verwenden.
In [ ]:
with torch.no_grad():
model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())
model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())
In [ ]:
iterations = 10
worker_iters = 5
for a_iter in range(iterations):
bobs_model = model.copy().send(bob)
alices_model = model.copy().send(alice)
bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)
alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)
for wi in range(worker_iters):
# Train Bob's Model
bobs_opt.zero_grad()
bobs_pred = bobs_model(bobs_data)
bobs_loss = ((bobs_pred - bobs_target)**2).sum()
bobs_loss.backward()
bobs_opt.step()
bobs_loss = bobs_loss.get().data
# Train Alice's Model
alices_opt.zero_grad()
alices_pred = alices_model(alices_data)
alices_loss = ((alices_pred - alices_target)**2).sum()
alices_loss.backward()
alices_opt.step()
alices_loss = alices_loss.get().data
alices_model.move(secure_worker)
bobs_model.move(secure_worker)
with torch.no_grad():
model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())
model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())
print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss))
Zu guter Letzt muss noch sicher gestellt werden, dass das finale Model korrekt gelernt hat. Deshalb wird es auf einem Test-Datensatz evaluiert. In diesem Fall wird dafür der Original-Datensatz verwendet. In der Praxis sollte jedoch ein neuer Datensatz genutzt werden, um zu prüfen wie gut sich das Model auf Ungesehenes generalisieren lässt.
In [ ]:
preds = model(data)
loss = ((preds - target) ** 2).sum()
In [ ]:
print(preds)
print(target)
print(loss.data)
In diesem kleinen Beispiel weist das gemittelte Model eine zu kleine Anpassung, verglichen mit dem lokal auf Rohdaten trainierten Model, auf. Jedoch konnte das Model trainiert werden ohne dabei die Daten des Einzelnen preiszugeben.
Auch war es möglich die Model-Updates von den einzelnen Helfern auf einem vertrauenswürdigen Helfer zu sammeln und somit den Verlust der Privatsphäre an den Model-Besitzer zu verhinden.
In einem noch kommenden Tutorial wird es darum gehen mit dem vertrauenswürdigen Mitteln die Gradienten selbst zu nutzen und dann mit diesen besseren Gradienten zu einem stabileren Model zu gelangen.
Herzlichen Glückwunsch zum Abschluss dieses Notebook-Tutorials! Wenn es Ihnen gefallen hat und Sie sich der Bewegung zur Wahrung der Privatsphäre, zum dezentralisiertenen Besitz von KI und der KI-Lieferkette (Daten) anschließen möchten, können Sie dies auf folgende Weise tun!
Der einfachste Weg, unserer Community zu helfen, besteht darin, die GitHub-Repos mit Sternen auszuzeichnen! Dies hilft, das Bewusstsein für die coolen Tools zu schärfen, die wir bauen.
Der beste Weg, um über die neuesten Entwicklungen auf dem Laufenden zu bleiben, ist, sich unserer Community anzuschließen! Sie können dies tun, indem Sie das Formular unter http://slack.openmined.org ausfüllen.
Der beste Weg, um zu unserer Community beizutragen, besteht darin, Entwickler zu werden! Sie können jederzeit zur PySyft GitHub Issues-Seite gehen und nach "Projects" filtern. Dies zeigt Ihnen alle Top-Level-Tickets und gibt einen Überblick darüber, an welchen Projekten Sie teilnehmen können! Wenn Sie nicht an einem Projekt teilnehmen möchten, aber ein wenig programmieren möchten, können Sie auch nach weiteren "einmaligen" Miniprojekten suchen, indem Sie nach GitHub-Problemen suchen, die als "good first issue" gekennzeichnet sind.
Wenn Sie keine Zeit haben, zu unserer Codebase beizutragen, aber dennoch Unterstützung leisten möchten, können Sie auch Unterstützer unseres Open Collective werden. Alle Spenden fließen in unser Webhosting und andere Community-Ausgaben wie Hackathons und Meetups!
In [ ]: